// fields.cpp
// Customizer
// Protea Customizer / Business Logic for managing fields
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "customizer.h"

//@ SEC 2
//
//@ CHA AddField
//@ COD AddField
//@ NUM 190
//@ CRI FIELD_NAME
//@ TAB FIELD_DESCRIPTOR Write 
//@ TAB FIELD_NBR_POOL Write
//@ TAB APPL_DEFN Write
//
//@ GEN AddField will create a new field and write a new FIELD_DESCRIPTR record
//
TRANSACTION_CODE( AddField ) 
{
	//@ GRS Start the transaction
	START_TXN( AddField );
		//@ GRS Start database transaction
		START_DB_TXN();
			AddFieldInternal( &txnvars, false );
		END_DB_TXN();

		LOG_TRANSACTION();
		//@ GRE End Database transaction
	CLEANUP_TXN();
	END_TXN();
	//@ GRE End the transaction
};







//
//@ CHA DelField
//@ COD DelField
//@ NUM 190
//@ CRI FIELD_NAME
//@ TAB FIELD_DESCRIPTOR Write 
//@ TAB FIELD_NBR_POOL Write 
//
//@ GEN DelField will delete FIELD_DESCRIPTR records
//
TRANSACTION_CODE( DeleteField ) {
	//@ GRS Start the transaction
	START_TXN( DeleteField );
		START_DB_TXN();
			DelFieldInternal( &txnvars, false );
		END_DB_TXN();

		LOG_TRANSACTION();
	CLEANUP_TXN();
	END_TXN();
	//@ GRE End the transaction
};





//
//@ CHA ChgField
//@ COD ChgField
//@ NUM 190
//@ CRI FIELD_NAME
//@ CRI APPL_NBR
//@ TAB FIELD_DESCRIPTOR Write
//
//@ GEN ChgField will change FIELD_DESCRIPTOR records
//
TRANSACTION_CODE( ChgField ) {

	//@ GRS Start the transaction
	START_TXN( ChgField );
		START_DB_TXN();
			ChgFieldInternal( &txnvars, false );
		END_DB_TXN();

		LOG_TRANSACTION();

		//@ Return the output buffer
		App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

	CLEANUP_TXN();
	END_TXN();
	//@ GRE End the transaction
};







//
//@ CHA RevField
//@ COD RevField
//@ NUM 190
//@ CRI FIELD_NAME
//@ CRI APPL_NBR
//@ TAB FIELD_DESCRIPTOR Write
//
//@ GEN RevField will read FIELD_DESCRIPTOR records
//
TRANSACTION_CODE( RevField ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* Msg_Defn = NULL;

	bool got_message = false;

	//@ GRS Start the transaction
	START_TXN( RevField );

		//@ Create a FIELD_DESCRIPTOR buffer
		TransBuf = App->CreateBuffer( FMT_FIELD_DESCRIPTOR, true );

		//@ Move supplied buffer information into transaction buffer
		TransBuf->MoveCorresponding( txnvars.buffer, txnvars.Errors, true );

		//@ Check for errors.
		txnvars.Errors->Check();

		START_DB_TXN();
			XCField* fld_number = TransBuf->GetField( FLD_FIELD_NUMBER );
			if (fld_number && !fld_number->IsBlank() && fld_number->GetLong(true) != 0) {
				//@ SUB FormatDescRetrieve Verify the we do have a format with this number
				//@ ERR E (DOESNT_EXIST) Format doesn't exist
				if (!FieldDescRetrieve( TransBuf, &txnvars ))
					txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_FIELD_NUMBER, 1, ERR_FIELD );
			} else {
				//@ SUB FieldDescValidate to validate input data
				FieldDescVerify( TransBuf, VERIFY_REVIEW, &txnvars, false );

				//@ SUB FieldDescRetrieve to obtain record data
				FieldDescRetrieve( TransBuf, &txnvars );
			};

			//@ If MSG_TEXT field exists, then fill it in
			if (txnvars.buffer->GetField( FLD_MSG_TEXT )) {
				//@ GRS

				//@ Create a MSG_DEFN buffer
				Msg_Defn = txnvars.myapp->CreateBuffer( FMT_MSG_DEFN );

				//@ Move in screen values
				Msg_Defn->MoveCorresponding( txnvars.buffer, txnvars.Errors );
				Msg_Defn->MoveUnlikeField( FLD_MSG_NBR, TransBuf, FLD_DESC_MESSAGE );

				//@ SUB MessageDefnRetrieve Retrieve the MSG_DEFN record
				if (MessageDefnRetrieve( Msg_Defn, &txnvars ))
					got_message = true;
				//@ GRE
			};

			//@ Clear the output buffer
			txnvars.buffer->Clear();

			//@ Move corresponding values from the transaction buffer to the Output buffer
			txnvars.buffer->MoveCorresponding( TransBuf, txnvars.Errors );

			//@ If we looked up the message number, then move MSG_TEXT value into screen
			if (got_message)
					txnvars.buffer->MoveField( Msg_Defn, FLD_MSG_TEXT, true );
		END_DB_TXN();

		txnvars.buffer->MoveCorresponding( TransBuf, txnvars.Errors );
		App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

	CLEANUP_TXN();
		App->CleanupObjects( 2, &TransBuf, &Msg_Defn );
	END_TXN();
	//@ GRE End the transaction
};





//
//@ CHA RevFields
//@ COD RevFields
//@ NUM 190
//@ CRI APPL_NBR
//@ TAB FIELD_DESCRIPTOR Read
//
//@ GEN RevFields returns a list of currently available fields
//
TRANSACTION_CODE( RevFields ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* detail = NULL;
	XCBuffer* countbuf = NULL;
	XCDBStatement* stmt = NULL;

	XCField* temp = NULL;

	//@ GRS Start the transaction
	START_TXN( RevFields );

		//@ Create format descriptor buffer
		TransBuf = App->CreateBuffer( FMT_FIELD_DESCRIPTOR, false );

		//@ Move screen info to transaction buffer
		TransBuf->MoveCorresponding( txnvars.buffer, txnvars.Errors );

		//@ Start the database transaction
		XCField* start = NULL;
		XCField* finish = NULL;
		XCField* partial = NULL;
		bool count_only = false;

		START_DB_TXN();
			XCSQLGen* query = txnvars.query;
			XCField* list[7];
			XCCompare comptemp[6];
			XCOrder order;
			int fcount = 0;

			// Always by appl number
			list[ fcount++ ] = TransBuf->GetField( FLD_APPL_NBR );

			// Search criteria
			temp = txnvars.buffer->GetField( FLD_START_STRING );
			if (temp && !temp->IsBlank()) {
				start = TransBuf->GetField( FLD_FIELD_NAME )->Clone();
				start->MoveField( temp );
				list[ fcount ] = start;
				comptemp[ fcount++ ].comparison = cmp_greaterthanequals;
			};
			temp = txnvars.buffer->GetField( FLD_FINISH_STRING );
			if (temp && !temp->IsBlank()) {
				finish = TransBuf->GetField( FLD_FIELD_NAME )->Clone();
				finish->MoveField( temp );
				list[ fcount ] = finish;
				comptemp[ fcount++ ].comparison = cmp_lessthanequals;
			};
			temp = txnvars.buffer->GetField( FLD_PARTIAL_STRING );
			if (temp && !temp->IsBlank()) {
				partial = TransBuf->GetField( FLD_FIELD_NAME )->Clone();
				partial->MoveField( temp );
				list[ fcount ] = partial;

				// Is this a partial search, or an exact field?
				if (strchr( temp->GetStringPtr(), '%' ))
					comptemp[ fcount ].comparison = cmp_like;
				fcount++;
			};
			temp = txnvars.buffer->GetField( FLD_DATA_TYPE );
			if (temp && !temp->IsBlank())
				list[ fcount++ ] = TransBuf->GetField( FLD_DATA_TYPE );
			list[ fcount ] = NULL;

			// Determine if we are doing a count only
			temp = txnvars.buffer->GetField( FLD_RESULT_COUNT );
			if (temp && temp->GetLong( true ) == 1)
				count_only = true;

			// Create the SQL statement
			if (count_only) {
				countbuf = query->MakeCOUNT( TransBuf );
			} else {
				query->MakeSELECT( TransBuf );
			};
			query->AddWHERE( list, comptemp );

			// Only add ORDERBY clause when actually grabbing data
			if (!count_only)
				query->AddORDERBY( FLD_FIELD_NAME, &order );

			// Get the data
			if (count_only) {
				stmt = txnvars.dbtxn->ExecuteSQL( query );

				temp->MoveField( countbuf->GetFieldByIndex(0) );
				App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
			} else {
				App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

				int child = txnvars.buffer->GetChildFormat();
				if (child) {
					detail = App->CreateBuffer( child, true );

					stmt = txnvars.dbtxn->ExecuteSQL( query );
					while (!stmt->Eof()) {
						detail->MoveCorresponding( TransBuf, txnvars.Errors, true );
						App->TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
						stmt->MoveNext();
					};
				};
			};
		END_DB_TXN();

	CLEANUP_TXN();
		App->CleanupObjects( 4, &TransBuf, &detail, &stmt, &countbuf );
	END_TXN();
	//@ GRE End the transaction
};





//
//@ CHA Copy Field
//@ COD CopyField
//@ CRI FIELD_NAME
//@ CRI APPL_NBR
//@ TAB FIELD_DESCRIPTOR Write
//
//@ GEN CopyField will create a copy of a FIELD_DESCRIPTOR record
//
TRANSACTION_CODE( CopyField ) {
	//@ GRS Start the transaction
	START_TXN( CopyField );
		START_DB_TXN();
			CopyFieldInternal( &txnvars, false );
		END_DB_TXN();

		LOG_TRANSACTION();
	CLEANUP_TXN();
	END_TXN();
	//@ GRE End the transaction
};
